﻿using Away.IdentityServer.Core.Utils;

namespace Away.IdentityServer.Core.Repositories.Impl;

[ServiceInject(ServiceLifetime.Scoped)]
public class ClientRepository : ConfigurationRepository, IClientRepository
{
    public ClientRepository(ConfigurationDbContext context) : base(context)
    {
    }

    public IResult Page(ClientSearch search)
    {
        var query = Query<Client>()
            .Include(o => o.ClientSecrets)
            .Include(o => o.AllowedGrantTypes)
            .Include(o => o.RedirectUris)
            .Include(o => o.PostLogoutRedirectUris)
            .Include(o => o.AllowedScopes)
            .Include(o => o.IdentityProviderRestrictions)
            .Include(o => o.Claims)
            .Include(o => o.AllowedCorsOrigins)
            .Include(o => o.Properties);

        var where = CondBuilder.New<Client>(true)
        .And(!string.IsNullOrWhiteSpace(search.Name), o => o.ClientName.Contains(search.Name!));

        var total = query.Count();
        var items = query.OrderBy(o => o.Id).Page(search).ToList();
        return ApiResult.Page(total, items);
    }

    public void Remove(List<int> ids)
    {
        var items = Query<Client>().Where(o => ids.Any(oo => oo == o.Id)).ToArray();
        if (items.Length == 0)
        {
            return;
        }
        Remove(items);
        Save();
    }

    public void Save(Client model)
    {
        Update(model);
        Save();

        var propertyIds = model.Properties.Select(o => o.Id);
        var claimIds = model.Claims.Select(o => o.Id);
        var secretIds = model.ClientSecrets.Select(o => o.Id);
        var allowedGrantTypeIds = model.AllowedGrantTypes.Select(o => o.Id);
        var redirectUriIds = model.RedirectUris.Select(o => o.Id);
        var postLogoutRedirectUriIds = model.PostLogoutRedirectUris.Select(o => o.Id);
        var allowedScopeIds = model.AllowedScopes.Select(o => o.Id);
        var identityProviderRestrictionIds = model.IdentityProviderRestrictions.Select(o => o.Id);
        var allowedCorsOriginIds = model.AllowedCorsOrigins.Select(o => o.Id);

        var sql = SqlBuilder.New();
        sql.Delete("\"ClientProperties\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(propertyIds.Any(), $"\"Id\" NOT IN ({string.Join(",", propertyIds)})")
            .End();

        sql.Delete("\"ClientClaims\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(claimIds.Any(), $"\"Id\" NOT IN ({string.Join(",", claimIds)})")
            .End();

        sql.Delete("\"ClientSecrets\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(secretIds.Any(), $"\"Id\" NOT IN ({string.Join(",", secretIds)})")
            .End();

        sql.Delete("\"ClientGrantTypes\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(allowedGrantTypeIds.Any(), $"\"Id\" NOT IN ({string.Join(",", allowedGrantTypeIds)})")
            .End();

        sql.Delete("\"ClientRedirectUris\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(redirectUriIds.Any(), $"\"Id\" NOT IN ({string.Join(",", redirectUriIds)})")
            .End();

        sql.Delete("\"ClientPostLogoutRedirectUris\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(postLogoutRedirectUriIds.Any(), $"\"Id\" NOT IN ({string.Join(",", postLogoutRedirectUriIds)})")
            .End();

        sql.Delete("\"ClientScopes\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(allowedScopeIds.Any(), $"\"Id\" NOT IN ({string.Join(",", allowedScopeIds)})")
            .End();

        sql.Delete("\"ClientIdPRestrictions\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(identityProviderRestrictionIds.Any(), $"\"Id\" NOT IN ({string.Join(",", identityProviderRestrictionIds)})")
            .End();

        sql.Delete("\"ClientCorsOrigins\"")
            .Where($"\"ClientId\"={model.Id}")
            .And(allowedCorsOriginIds.Any(), $"\"Id\" NOT IN ({string.Join(",", allowedCorsOriginIds)})")
        .End();

        DB.Database.ExecuteSqlRaw(sql.ToSql());
    }
}
